package com.bsg.upm.check;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bsg.upm.constant.Messages;
import com.bsg.upm.entity.AreaEntity;
import com.bsg.upm.entity.ClusterEntity;
import com.bsg.upm.entity.NetworkingEntity;
import com.bsg.upm.exception.APIException;
import com.bsg.upm.service.NetworkingService;

/**
 * 集群业务处理检查
 * 
 * @author HCK
 *
 */
@Service
public class ClusterCheck extends BaseCheck {

	@Resource
	private NetworkingService networkingService;

	/**
	 * 新增时检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 */
	public CheckResult checkSave(Map<String, Object> paramMap) {
		// 非逻辑检查
		CheckResult chkRS = checkSaveNonLogic(paramMap);
		if (chkRS.isError()) {
			return chkRS;
		}

		// 逻辑检查
		chkRS = checkSaveLogic(paramMap);
		if (chkRS.isError()) {
			return chkRS;
		}
		return chkRS;
	}

	/**
	 * 集群编辑时检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public CheckResult checkUpdate(Map<String, Object> paramMap) throws APIException {
		// 非逻辑检查
		CheckResult chkRS = checkUpdateNonLogic(paramMap);
		if (chkRS.isError()) {
			return chkRS;
		}

		// 逻辑检查
		chkRS = checkUpdateLogic(paramMap);
		if (chkRS.isError()) {
			return chkRS;
		}
		return chkRS;
	}

	/**
	 * 集群启用时检查
	 * 
	 * @param cluster
	 *            集群对象
	 * @return CheckResult检查结果对象
	 */
	public CheckResult checkEnable(ClusterEntity cluster) {
		CheckResult chkRS = new CheckResult();
		// 存在性检查
		if (cluster == null) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "集群"));
			return chkRS;
		}

		// 集群状态检查
		if (cluster.getEnabled()) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg(Messages.ENABLED_ALREADY);
			return chkRS;
		}
		return chkRS;
	}

	/**
	 * 集群停用时检查
	 * 
	 * @param cluster
	 *            集群对象
	 * @return CheckResult检查结果对象
	 */
	public CheckResult checkDisable(ClusterEntity cluster) {
		CheckResult chkRS = new CheckResult();
		// 存在性检查
		if (cluster == null) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "集群"));
			return chkRS;
		}

		// 集群状态检查
		if (!cluster.getEnabled()) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(Messages.DISABLED_ALREADY);
			return chkRS;
		}
		return chkRS;
	}

	/**
	 * 集群删除时检查
	 * 
	 * @param cluster
	 *            集群对象
	 * @return CheckResult检查结果对象
	 */
	public CheckResult checkRemove(ClusterEntity cluster) {
		CheckResult chkRS = new CheckResult();
		// 存在性检查
		if (cluster == null) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "集群"));
			return chkRS;
		}

		// 集群状态检查
		if (cluster.getEnabled()) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg(MessageFormat.format(Messages.ENABLED_NOT_DELETE, "集群"));
			return chkRS;
		}

		// 集群关联资源检查
		if (hostDao.countByClusterId(cluster.getId()) > 0) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg("该集群已关联主机，无法删除");
			return chkRS;
		}
		return chkRS;
	}

	/**
	 * 新增时非业务逻辑(非空和长度)检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 */
	@SuppressWarnings("unchecked")
	private CheckResult checkSaveNonLogic(Map<String, Object> paramMap) {
		CheckResult chkRS = new CheckResult();
		// 区域非空检查
		String areaId = (String) paramMap.get("area");
		if (StringUtils.isBlank(areaId)) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "所属区域"));
			return chkRS;
		}

		// 集群名称非空和长度检查
		String name = (String) paramMap.get("name");
		if (StringUtils.isBlank(name)) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "集群名称"));
			return chkRS;
		}
		if (StringUtils.trim(name).length() > 64) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.MAXLENGTH_NOT_ALLOWED, "集群名称", 64));
			return chkRS;
		}

		// 包含软件非空检查
		List<String> dfSubServNames = (List<String>) paramMap.get("definitionSubServs");
		if (dfSubServNames == null || dfSubServNames.size() == 0) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "包含软件"));
			return chkRS;
		}

		// 所用网段非空检查
		List<String> networkingIds = (List<String>) paramMap.get("networkings");
		if (networkingIds == null || networkingIds.size() == 0) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "网段"));
			return chkRS;
		}

		// 最大使用率非空和有效性检查
		Integer maxUsage = (Integer) paramMap.get("maxUsage");
		if (maxUsage == null) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "最大使用率"));
			return chkRS;
		}
		if (maxUsage < 0 || maxUsage > 100) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.BETWEEN_MIN_AND_MAX, "最大使用率", 0, 100));
			return chkRS;
		}

		// 最大主机数量非空和有效性检查
		Integer maxHostCount = (Integer) paramMap.get("maxHostCount");
		if (maxHostCount == null) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "最大主机数量"));
			return chkRS;
		}
		if (maxHostCount < 1 || maxHostCount > 100) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.BETWEEN_MIN_AND_MAX, "最大主机数量", 1, 100));
			return chkRS;
		}

		if (paramMap.containsKey("description")) {
			// 描述长度检查
			String description = (String) paramMap.get("description");
			if (StringUtils.trim(description).length() > 256) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.MAXLENGTH_NOT_ALLOWED, "描述", 256));
				return chkRS;
			}
		}

		return chkRS;
	}

	/**
	 * 新增时业务逻辑检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 */
	@SuppressWarnings("unchecked")
	private CheckResult checkSaveLogic(Map<String, Object> paramMap) {
		CheckResult chkRS = new CheckResult();
		// 区域存在性检查
		String areaId = (String) paramMap.get("area");
		AreaEntity area = areaDao.get(areaId);
		if (area == null) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "所属区域"));
			return chkRS;
		}

		// 区域状态检查
		if (!area.getEnabled()) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.DISABLED_NOT_SELECT, "所属区域"));
			return chkRS;
		}

		// 集群名称重复性检查
		String name = (String) paramMap.get("name");
		if (clusterDao.countByAreaIdAndName(areaId, name) > 0) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg(MessageFormat.format(Messages.EXIST, "区域下集群名称"));
			return chkRS;
		}

		// 混合状态和包含软件关联检查
		Boolean mixed = (Boolean) paramMap.get("mixed");
		List<String> dfSubServNames = (List<String>) paramMap.get("definitionSubServs");
		if (mixed == false && dfSubServNames.size() > 1) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg("非混合部署只能选择一个包含软件");
			return chkRS;
		}

		// 包含软件存在性检查
		for (String dfSubServName : dfSubServNames) {
			if (definitionSubServDao.listByDefinitionSubServName(dfSubServName).size() == 0) {
				chkRS.setStatus(HttpStatus.SC_GONE);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "包含软件"));
				return chkRS;
			}
		}

		List<String> networkingIds = (List<String>) paramMap.get("networkings");
		for (String networkingId : networkingIds) {
			// 网段存在性检查
			NetworkingEntity networking = networkingDao.get(networkingId);
			if (networking == null) {
				chkRS.setStatus(HttpStatus.SC_GONE);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "网段"));
				return chkRS;
			}

			// 网段状态检查
			if (!networking.getEnabled()) {
				chkRS.setStatus(HttpStatus.SC_GONE);
				chkRS.setErrorMsg(MessageFormat.format(Messages.DISABLED_NOT_SELECT, "网段"));
				return chkRS;
			}

			// 网段关联集群检查(一个网段只能被一个集群使用)
			if (networking.getCluster() != null && StringUtils.isNotBlank(networking.getCluster().getId())) {
				chkRS.setStatus(HttpStatus.SC_CONFLICT);
				chkRS.setErrorMsg("网段已关联其他集群");
				return chkRS;
			}
		}

		return chkRS;
	}

	/**
	 * 编辑时非业务逻辑(非空和长度)检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 */
	@SuppressWarnings("unchecked")
	private CheckResult checkUpdateNonLogic(Map<String, Object> paramMap) {
		CheckResult chkRS = new CheckResult();
		// 集群非空检查
		String clusterId = (String) paramMap.get("clusterId");
		if (StringUtils.isBlank(clusterId)) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "集群编码"));
			return chkRS;
		}

		if (paramMap.containsKey("area")) {
			// 区域非空检查
			String areaId = (String) paramMap.get("area");
			if (StringUtils.isBlank(areaId)) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "所属区域"));
				return chkRS;
			}
		}

		if (paramMap.containsKey("name")) {
			// 名称非空和长度检查
			String name = (String) paramMap.get("name");
			if (StringUtils.isBlank(name)) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "集群名称"));
				return chkRS;
			}
			if (StringUtils.trim(name).length() > 64) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.MAXLENGTH_NOT_ALLOWED, "集群名称", 64));
				return chkRS;
			}
		}

		if (paramMap.containsKey("definitionSubServs")) {
			// 包含软件非空检查
			List<String> dfSubServNames = (List<String>) paramMap.get("definitionSubServs");
			if (dfSubServNames == null || dfSubServNames.size() == 0) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "包含软件"));
				return chkRS;
			}
		}

		if (paramMap.containsKey("networkings")) {
			// 所用网段非空检查
			List<String> networkingIds = (List<String>) paramMap.get("networkings");
			if (networkingIds == null || networkingIds.size() == 0) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "网段"));
				return chkRS;
			}
		}

		if (paramMap.containsKey("maxUsage")) {
			// 最大使用率非空检查
			Integer maxUsage = (Integer) paramMap.get("maxUsage");
			if (maxUsage == null) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "最大使用率"));
				return chkRS;
			}
			if (maxUsage < 0 || maxUsage > 100) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.BETWEEN_MIN_AND_MAX, "最大使用率", 0, 100));
				return chkRS;
			}
		}

		if (paramMap.containsKey("maxHostCount")) {
			// 最大主机数量非空检查
			Integer maxHostCount = (Integer) paramMap.get("maxHostCount");
			if (maxHostCount == null) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "最大主机数量"));
				return chkRS;
			}
			if (maxHostCount < 1 || maxHostCount > 100) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.BETWEEN_MIN_AND_MAX, "最大主机数量", 1, 100));
				return chkRS;
			}
		}

		if (paramMap.containsKey("description")) {
			// 描述长度检查
			String description = (String) paramMap.get("description");
			if (StringUtils.trim(description).length() > 256) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg(MessageFormat.format(Messages.MAXLENGTH_NOT_ALLOWED, "描述", 256));
				return chkRS;
			}
		}
		return chkRS;
	}

	/**
	 * 编辑时业务逻辑检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 */
	@SuppressWarnings("unchecked")
	private CheckResult checkUpdateLogic(Map<String, Object> paramMap) throws APIException {
		CheckResult chkRS = new CheckResult();
		// 集群存在性检查
		String clusterId = (String) paramMap.get("clusterId");
		ClusterEntity cluster = clusterDao.get(clusterId);
		if (cluster == null) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "集群"));
			return chkRS;
		}

		// 集群状态检查
		if (cluster.getEnabled()) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg(MessageFormat.format(Messages.ENABLED_NOT_UPDATE, "集群"));
			return chkRS;
		}

		AreaEntity area = cluster.getArea();
		String areaId = area.getId();
		String siteId = area.getSite().getId();
		// 该集群下已入库的主机的数量
		int inputHostNum = hostDao.countInputByClusterId(clusterId);

		if (paramMap.containsKey("area")) {
			areaId = (String) paramMap.get("area");
			if (!area.getId().equals(areaId)) {
				// 如果该集群下的主机已经入库，则不允许变更区域
				if (inputHostNum != 0) {
					chkRS.setStatus(HttpStatus.SC_CONFLICT);
					chkRS.setErrorMsg("该集群关联的主机已入库，无法变更区域");
					return chkRS;
				}

				// 区域存在性检查
				AreaEntity newArea = areaDao.get(areaId);
				if (newArea == null) {
					chkRS.setStatus(HttpStatus.SC_GONE);
					chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "所属区域"));
					return chkRS;
				}

				// 区域状态检查
				if (!newArea.getEnabled()) {
					chkRS.setStatus(HttpStatus.SC_GONE);
					chkRS.setErrorMsg(MessageFormat.format(Messages.DISABLED_NOT_SELECT, "所属区域"));
					return chkRS;
				}
			}
		}

		if (paramMap.containsKey("name")) {
			String name = (String) paramMap.get("name");
			if (!name.equals(cluster.getName())) {
				// 集群名称重复性检查
				if (clusterDao.countByAreaIdAndName(areaId, name) > 0) {
					chkRS.setStatus(HttpStatus.SC_CONFLICT);
					chkRS.setErrorMsg(MessageFormat.format(Messages.EXIST, "区域下集群名称"));
					return chkRS;
				}
			}
		}

		if (paramMap.containsKey("definitionSubServs")) {
			List<String> dfSubServNames = (List<String>) paramMap.get("definitionSubServs");
			Boolean mixed = cluster.getMixed();
			if (paramMap.containsKey("mixed")) {
				mixed = (Boolean) paramMap.get("mixed");
			}

			if (mixed == false && dfSubServNames.size() > 1) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg("非混合部署只能选择一个包含软件");
				return chkRS;
			}

			if (changedDefinitionSubServNames(dfSubServNames, cluster.getDefinitionSubServNames())) {
				// 如果该集群下的主机已经入库，则不允许变更包含软件
				if (inputHostNum != 0) {
					chkRS.setStatus(HttpStatus.SC_CONFLICT);
					chkRS.setErrorMsg("该集群关联的主机已入库，无法变更包含软件");
					return chkRS;
				}

				// 包含软件存在性检查
				for (String dfSubServName : dfSubServNames) {
					if (definitionSubServDao.listByDefinitionSubServName(dfSubServName).size() == 0) {
						chkRS.setStatus(HttpStatus.SC_GONE);
						chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "包含软件"));
						return chkRS;
					}
				}
			}
		}

		if (paramMap.containsKey("networkings")) {
			List<String> networkingIds = (List<String>) paramMap.get("networkings");
			List<NetworkingEntity> networkings = cluster.getNetworkings();
			List<String> addNetworkingIds = listNewAddNetworkingIds(networkings, networkingIds);
			List<String> removeNetworkingIds = listRemoveNetworkingIds(networkings, networkingIds);

			// 新追加的网段检查
			for (String networkingId : addNetworkingIds) {
				NetworkingEntity networking = networkingDao.get(networkingId);
				// 存在性检查
				if (networking == null) {
					chkRS.setStatus(HttpStatus.SC_GONE);
					chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "网段"));
					return chkRS;
				}

				// 状态检查
				if (!networking.getEnabled()) {
					chkRS.setStatus(HttpStatus.SC_GONE);
					chkRS.setErrorMsg(MessageFormat.format(Messages.DISABLED_NOT_SELECT, "网段"));
					return chkRS;
				}

				// 网段关联资源检查
				if (networking.getCluster() != null && StringUtils.isNotBlank(networking.getCluster().getId())) {
					chkRS.setStatus(HttpStatus.SC_CONFLICT);
					chkRS.setErrorMsg("网段:" + networking.getName() + "已关联其他集群");
					return chkRS;
				}
			}

			// 删除的网段检查
			for (String networkingId : removeNetworkingIds) {
				JSONObject mgmNetworkingInfo = networkingService.getNetworkingInfoFromMGM(siteId, networkingId);
				JSONArray ipJsonArr = mgmNetworkingInfo.getJSONArray("IPs");
				for (int i = 0; i < ipJsonArr.size(); i++) {
					JSONObject ipJson = ipJsonArr.getJSONObject(i);
					if (!StringUtils.isBlank(ipJson.getString("unit_id"))
							|| !StringUtils.isBlank(ipJson.getString("engine_id"))) {
						chkRS.setStatus(HttpStatus.SC_CONFLICT);
						chkRS.setErrorMsg("存在网段已关联服务, 不能删除原网段");
						return chkRS;
					}
				}
			}
		}

		return chkRS;
	}

	private List<String> listNewAddNetworkingIds(List<NetworkingEntity> networkings, List<String> networkingIds) {
		List<String> list = new ArrayList<String>();
		for (String networkingId : networkingIds) {
			boolean exist = false;
			for (NetworkingEntity networking : networkings) {
				if (networking.getId().equals(networkingId)) {
					exist = true;
					break;
				}
			}

			if (!exist) {
				list.add(networkingId);
			}
		}
		return list;
	}

	private List<String> listRemoveNetworkingIds(List<NetworkingEntity> networkings, List<String> networkingIds) {
		List<String> list = new ArrayList<String>();
		for (NetworkingEntity networking : networkings) {
			boolean exist = false;
			for (String networkingId : networkingIds) {
				if (networking.getId().equals(networkingId)) {
					exist = true;
					break;
				}
			}
			if (!exist) {
				list.add(networking.getId());
			}
		}
		return list;
	}

	private boolean changedDefinitionSubServNames(List<String> dfSubServNames, String dfSubServNames_original) {
		List<String> originalNames = Arrays.asList(dfSubServNames_original.split(","));
		if (dfSubServNames.size() != originalNames.size()) {
			return true;
		}
		Collections.sort(dfSubServNames);
		Collections.sort(originalNames);
		for (int i = 0; i < dfSubServNames.size(); i++) {
			if (!dfSubServNames.get(i).equals(originalNames.get(i))) {
				return true;
			}
		}
		return false;
	}

}
